using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using Microsoft.Build.Evaluation;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

using SceneEngine;

using DialogResult = System.Windows.Forms.DialogResult;

using TreeNode = System.Windows.Forms.TreeNode;
using TreeNodeCollection = System.Windows.Forms.TreeNodeCollection;

using ButtonEnabled = ComponentFactory.Krypton.Toolkit.ButtonEnabled;
using Microsoft.Build.Execution;

namespace SceneEditor
{
    /// <summary>
    /// A component that manages all editor activities.
    /// </summary>
    public partial class Editor : DrawableGameComponent
    {
        #region Fields
        private Random random = new Random();

        // Editor forms.
        private UI.Editor editor;
        private UI.EditorSplash splash;

        private PreferencesForm preferences;

        // General purpose camera.
        private ICamera camera;

        // Asset fields.
        private ContentBuilder contentBuilder;
        private ModelManager modelManager;

        // Scene fields.
        private string scenePath;
        private Scene scene;

        private bool changesMade;
        private bool terrainChangesMade;
        private bool colorMapChangesMade;

        // Gizmo fields.
        private Gizmo gizmo;

        private int gridLines = 50;
        private float gridSpacing = 100.0f;

        private LineRenderer lineRenderer;

        // Frame rate fields
        private int frameRate = 0;
        private int frameCounter = 0;

        private TimeSpan elapsedTime = TimeSpan.Zero;

        // Input fields.
        private MouseState mouseState;
        private MouseState prevMouseState;

        private KeyboardState keyboardState;
        private KeyboardState prevKeyState;

        private Ray mouseRay;

        // Selection fields.
        private Texture2D dottedLine;
        private Texture2D alphaRectangle;
        private Rectangle selectionBox;

        private bool placingObjects;
        private bool selectingObjects;

        // Under / redo fields.
        private StackList undoActions = new StackList(50);
        private StackList redoActions = new StackList(50);

        private object[] oldValues;

        private bool flatteningTerrain;

        private DepthStencilState LessThanDepthState = new DepthStencilState()
        {
            DepthBufferFunction = CompareFunction.Less
        };

        private RasterizerState WireFrameState = new RasterizerState()
        {
            FillMode = FillMode.WireFrame
        };

        public UI.Editor EditorForm
        {
            get { return editor; }
        }

        #endregion

        /// <summary>
        /// Constructs a new Editor object.
        /// </summary>
        public Editor(Game game)
            : base(game)
        {
            Game.IsMouseVisible = true;
        }

        /// <summary>
        /// Shows the loading screen of the editor, and 
        /// then links the editor to the selected project.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();

            splash = new UI.EditorSplash();

            if (splash.ShowDialog() != DialogResult.OK)
            {
                Game.Exit();
                Enabled = false;

                return;
            }

            // Create a new editor form object.
            editor = new UI.Editor();
            // Set up the forms events.
            SetUpEventHandlers();

            ShapeRenderer.Initialize(GraphicsDevice);

            editor.Show();

            InitializeEditor();
        }

        /// <summary>
        /// Links the editor to the selected project and 
        /// initializes the editors componenets.
        /// </summary>
        private void InitializeEditor()
        {
            string contentPath = splash.ContentPath;
            string projectPath = splash.ProjectPath;
            string scenePath = splash.ScenePath;

            LinkToProject(projectPath, contentPath);

            // Create the camera based on the preferences.
            if (Preferences.Default.MouseControls)
            {
                camera = new MayaStyleCamera(new Vector3(256, 60, 256), Preferences.Default.CameraSpeed);
            }
            else
            {
                camera = new Camera(new Vector3(256, 60, 256), Preferences.Default.CameraSpeed);
            }

            EngineGlobals.Camera = camera;

            lineRenderer = new LineRenderer(Preferences.Default.GridLineCount * 4);

            LoadContent();

            CreateNewScene();

            this.scenePath = scenePath;

            if (splash.NewScene == false)
            {
                splash.NewScene = false;
                scene.Load(scenePath);

                if (scene.HeightMap != null)
                {
                    scene.HeightMap.HeightMapChanged += new EventHandler(HeightMap_TextureChanged);
                    scene.HeightMap.ColorMapChanged += new EventHandler(HeightMap_ColorMapChanged);
                    UpdateTerrainTab(true);
                }
                else
                {
                    UpdateTerrainTab(false);
                }
            }

            editor.Text = Path.GetFileNameWithoutExtension(scenePath);

            gizmo = new Gizmo();
            gizmo.GridSpacing = Preferences.Default.GridSpacing;

            selectionBox = new Rectangle(-1, -1, 0, 0);

            InitializeGrid(Preferences.Default.GridSpacing,
                         Preferences.Default.GridLineCount,
                         Preferences.Default.GridColor);

            SetUpObjectTree();

            ViewScene();

            editor.Viewport.Focus();
        }

        /// <summary>
        /// Links the editor to the targeted project and
        /// initializes the Engine and Editor globals.
        /// </summary>
        private void LinkToProject(string projectPath, string contentPath)
        {
            // Load the targeted project.
            Project mainProject = EditorGlobals.GetProject(projectPath);

            // Try to build the content in the content project.
            string parentDirectory = TryBuildContent(projectPath, contentPath, mainProject);

            // Set Up Editor Globals
            contentBuilder = new ContentBuilder();

            EditorGlobals.Initialize(contentPath);

            EditorGlobals.BuiltContent = new ContentManager(Game.Services,
                contentBuilder.OutputDirectory);

            EditorGlobals.EditorContent = new ContentManager(Game.Services,
                Path.Combine(Directory.GetCurrentDirectory(), "Content"));

            // Set Up Engine Globals
            string contentDirectory = Path.Combine(parentDirectory, "Content");

            EngineGlobals.Initialize(Game.Services, GraphicsDevice);
            EngineGlobals.Content = new ContentManager(Game.Services, contentDirectory);
        }

        private static string TryBuildContent(string projectPath, string contentPath, Project mainProject)
        {
            string parentDirectory = mainProject.GetProperty("OutDir").EvaluatedValue;
            parentDirectory = Path.Combine(Path.GetDirectoryName(projectPath), parentDirectory);

            if (MessageBoxHelper.ShowTryBuildContent() == DialogResult.Yes)
            {
                System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.WaitCursor;

                ProjectInstance contentProjectInstance = EditorGlobals.GetProject(contentPath).CreateProjectInstance();

                contentProjectInstance.SetProperty("XNAContentPipelineTargetPlatform", "Windows");
                contentProjectInstance.SetProperty("XNAContentPipelineTargetProfile", "HiDef");
                contentProjectInstance.SetProperty("XnaFrameworkVersion", "v4.0");
                contentProjectInstance.SetProperty("Configuration", "Release");
                contentProjectInstance.SetProperty("ParentOutputDir", parentDirectory);

                // Hook up our custom error logger.
                ErrorLogger errorLogger = new ErrorLogger();

                BuildParameters buildParameters = new BuildParameters(ProjectCollection.GlobalProjectCollection);
                buildParameters.Loggers = new Microsoft.Build.Framework.ILogger[] { errorLogger };
                
                BuildManager.DefaultBuildManager.BeginBuild(buildParameters);

                BuildRequestData request = new BuildRequestData(contentProjectInstance, new string[0]);
                BuildSubmission submission = BuildManager.DefaultBuildManager.PendBuildRequest(request);
                
                submission.ExecuteAsync(null, null);

                // Wait for the build to finish.
                submission.WaitHandle.WaitOne();

                BuildManager.DefaultBuildManager.EndBuild();

                // If the build failed, return an error string.
                if (submission.BuildResult.OverallResult == BuildResultCode.Failure)
                {
                    string error = string.Join("\n", errorLogger.Errors.ToArray());
                    MessageBoxHelper.ShowErrorOccured();
                }

                System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Arrow;
            }
            return parentDirectory;
        }

        /// <summary>
        /// Creates a grid with the specefied properties.
        /// </summary>
        private void InitializeGrid(float gridSize, int lineCount, Color color)
        {
            lineRenderer.Clear();

            for (int i = 0; i < lineCount; i++)
            {
                lineRenderer.Submit(Vector3.Left * gridSize * i, (Vector3.Left * gridSize
                    * i) + Vector3.Forward * (gridSize * (lineCount - 1)), color);

                lineRenderer.Submit(Vector3.Forward * gridSize * i, (Vector3.Forward *
                    gridSize * i) + Vector3.Left * (gridSize * (lineCount - 1)), color);
            }
        }

        /// <summary>
        /// Creates a new scene and adds it the the 
        /// engine's services.
        /// </summary>
        private void CreateNewScene()
        {
            scene = new Scene();
            scene.ObjectRenamed += new SceneEngine.RenamedEventHandler(scene_ObjectRenamed);

            UpdateTerrainTab(false);
        }

        /// <summary>
        /// Prompts the user to save any changes.
        /// </summary>
        private bool PromptSaveChanges()
        {
            DialogResult saveSceneResult = DialogResult.No;

            if (changesMade)
            {
                saveSceneResult = System.Windows.Forms.MessageBox.Show(
                    "Do you want to save the changes to the current scene", "Scene Editor",
                    System.Windows.Forms.MessageBoxButtons.YesNoCancel,
                    System.Windows.Forms.MessageBoxIcon.Warning);

                if (saveSceneResult == DialogResult.Yes)
                {
                    tsSaveScene_Click(null, null);
                }
            }

            DialogResult saveTerrainChanges = DialogResult.No;
            DialogResult saveColorMapChanges = DialogResult.No;

            if (saveTerrainChanges == DialogResult.No)
            {
                if (terrainChangesMade)
                {
                    saveTerrainChanges = MessageBoxHelper.ShowSaveTerrainChanges();
                }
                if (colorMapChangesMade)
                {
                    saveColorMapChanges = MessageBoxHelper.ShowSaveColorMapChanges();
                }

                if (saveTerrainChanges == DialogResult.Yes)
                {
                    SaveHeightmap(null, null);
                }
                if (saveColorMapChanges == DialogResult.Yes)
                {
                    SaveColorMap(null, null);
                }
            }

            return saveSceneResult == DialogResult.Cancel ||
                   saveTerrainChanges == DialogResult.Cancel ||
                   saveColorMapChanges == DialogResult.Cancel;
        }

        /// <summary>
        /// Initializes the editors events.
        /// </summary>
        private void SetUpEventHandlers()
        {
            editor.HandleDestroyed += new EventHandler(HandleDestroyed);
            editor.FormClosing += new System.Windows.Forms.FormClosingEventHandler(editor_FormClosing);

            editor.tsNewLevel.Click += new EventHandler(tsNewScene_Click);
            editor.tsSaveLevel.Click += new EventHandler(tsSaveScene_Click);
            editor.tsSaveLevelAs.Click += new EventHandler(tsSaveSceneAs_Click);
            editor.tsOpenLevel.Click += new EventHandler(tsOpenScene_Click);

            editor.newToolStripButton.Click += new EventHandler(tsNewScene_Click);
            editor.openToolStripButton.Click += new EventHandler(tsOpenScene_Click);
            editor.saveToolStripButton.Click += new EventHandler(tsSaveScene_Click);

            editor.tvAssets.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(tvAssets_AddObject);
            editor.tvAssets.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(tvAssets_NodeMouseClick);
            editor.btnAddModelFolder.Click += new EventHandler(btnAddModelFolder_Click);
            editor.btnDeleteAssetMenu.Click += btnRemoveAsset_Click;
            editor.btnImportAssetMenu.Click += btnAddAsset_Click;

            editor.Viewport.SizeChanged += new EventHandler(Viewport_SizeChanged);

            editor.btnRemove.Click += new EventHandler(btnRemoveObject_Click);
            editor.btnRemoveAsset.Click += new EventHandler(btnRemoveAsset_Click);

            editor.tvObjects.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(tvObjects_SelectObject);
            editor.tvObjects.KeyUp += new System.Windows.Forms.KeyEventHandler(tvObjects_KeyUp);
            editor.btnAddObjectGroup.Click += new EventHandler(btnAddObjectGroup_Click);
            editor.tvObjects.NodeMoved += new TreeNodeMovedEventHandler(tvObjects_NodesMoved);

            editor.btnAddAsset.Click += new EventHandler(btnAddAsset_Click);

            editor.btnSnapToGrid.Click += new EventHandler(btnSnapToGrid_Click);
            editor.btnViewSelected.Click += new EventHandler(btnCenterCamera_Click);

            editor.btnTranslate.Click += new EventHandler(btnTranslate_Click);
            editor.btnRotate.Click += new EventHandler(btnRotate_Click);

            editor.tsViewSelected.Click += new EventHandler(btnCenterCamera_Click);

            editor.btnUndo.Click += new EventHandler(btnUndo_Click);
            editor.undoToolStripMenuItem.Click += new EventHandler(btnUndo_Click);

            editor.btnRedo.Click += new EventHandler(btnRedo_Click);
            editor.redoToolStripMenuItem.Click += new EventHandler(btnRedo_Click);

            editor.cbOrientation.SelectedIndexChanged += new EventHandler(cbOrientation_SelectedIndexChanged);
            editor.cbRotationMode.SelectedIndexChanged += new EventHandler(cbRotationMode_SelectedIndexChanged);
            editor.cbOrigin.SelectedIndexChanged += new EventHandler(cbOrigin_SelectedIndexChanged);

            editor.tsDuplicate.Click += new EventHandler(tsDuplicateObjects_Click);

            redoActions.Changed += new StackList.ChangedEventHandler(redoActions_Changed);
            undoActions.Changed += new StackList.ChangedEventHandler(undoActions_Changed);

            editor.propertyGrid.SelectedGridItemChanged += new System.Windows.Forms.SelectedGridItemChangedEventHandler(propertyGrid_SelectedGridItemChanged);
            editor.propertyGrid.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(propertyGrid_PropertyValueChanged);

            editor.tsSwitchProject.Click += new EventHandler(tsSwitchProject_Click);

            editor.tsSelectAll.Click += new EventHandler(tsSelectAll_Click);

            editor.tsOptions.Click += new EventHandler(tsOptions_Click);

            editor.tsFirstPerson.Click += new EventHandler(tsFirstPerson_Click);
            editor.tsMaya.Click += new EventHandler(tsMaya_Click);

            editor.btnCameras.ButtonClick += new EventHandler(btnCameras_ButtonClick);

            editor.btnHideScene.Click += new EventHandler(btnHideScene_Click);
            editor.btnHideModels.Click += new EventHandler(btnHideModels_Click);
            editor.btnHideProperties.Click += new EventHandler(btnHideProperties_Click);

            editor.toolControl.MouseClick += new System.Windows.Forms.MouseEventHandler(toolControl_MouseClick);

            editor.tsSolid.Click += new EventHandler(tsSolid_Click);
            editor.tsWire.Click += new EventHandler(tsWire_Click);

            editor.btnScale.Click += new EventHandler(btnScale_Click);

            editor.tsSnapToGrid.Click += new EventHandler(btnSnapToGrid_Click);

            editor.tsTranslateTool.Click += new EventHandler(btnTranslate_Click);
            editor.tsRotateTool.Click += new EventHandler(btnRotate_Click);
            editor.tsScaleTool.Click += new EventHandler(btnScale_Click);

            editor.tbCursorSize.ValueChanged += new EventHandler(tbCursorSize_ValueChanged);
            editor.tbCursorStrength.ValueChanged += new EventHandler(tbCursorStrength_ValueChanged);

            editor.generateColourMapToolStripMenuItem.Click += new EventHandler(generateColourMapToolStripMenuItem_Click);
            editor.smoothHeightMapToolStripMenuItem.Click += new EventHandler(smoothHeightMapToolStripMenuItem_Click);

            editor.randomToolStripMenuItem.Click += new EventHandler(randomToolStripMenuItem_Click);
            editor.randomToolStripMenuItem1.Click += new EventHandler(randomToolStripMenuItem1_Click);

            editor.perlinToolStripMenuItem.Click += new EventHandler(perlinToolStripMenuItem_Click);
            editor.perlinToolStripMenuItem1.Click += new EventHandler(perlinToolStripMenuItem1_Click);

            editor.toolControl.SelectedIndexChanged += new EventHandler(toolControl_SelectedIndexChanged);

            editor.tbMaxHeight.ValueChanged += new EventHandler(tbMaxHeight_ValueChanged);

            editor.btnSaveHeightmap.Click += new EventHandler(SaveHeightmap);
            editor.btnSaveColorMap.Click += new EventHandler(SaveColorMap);

            editor.pbHeightMap.Click += new EventHandler(LoadHeightMap);
            editor.pbColorMap.Click += new EventHandler(LoadColorMap);

            editor.btnCreateSmallTerrain.Click += new EventHandler(btnCreateSmallTerrain_Click);
            editor.btnCreateMediumTerrain.Click += new EventHandler(btnCreateMediumTerrain_Click);
            editor.btnCreateLargeTerrain.Click += new EventHandler(btnCreateLargeTerrain_Click);

            editor.btnClearHeightMap.Click += new EventHandler(btnClearHeightMap_Click);

            editor.tbTerrainTexture.SelectedIndex = 0;

            editor.tvAssets.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(tvAssets_NodeMouseClick);
            editor.tvAssets.MouseUp += new System.Windows.Forms.MouseEventHandler(tvAssets_MouseUp);

            editor.pbTerrainTexture1.MouseClick += new System.Windows.Forms.MouseEventHandler(pbTerrainTexture1_MouseClick);
            editor.pbTerrainTexture2.MouseClick += new System.Windows.Forms.MouseEventHandler(pbTerrainTexture2_MouseClick);
            editor.pbTerrainTexture3.MouseClick += new System.Windows.Forms.MouseEventHandler(pbTerrainTexture3_MouseClick);
            editor.pbTerrainTexture4.MouseClick += new System.Windows.Forms.MouseEventHandler(pbTerrainTexture4_MouseClick);

            editor.tbTerrainTexture1.ValueChanged += new EventHandler(tbTerrainTexture1_ValueChanged);
            editor.tbTerrainTexture2.ValueChanged += new EventHandler(tbTerrainTexture2_ValueChanged);
            editor.tbTerrainTexture3.ValueChanged += new EventHandler(tbTerrainTexture3_ValueChanged);
            editor.tbTerrainTexture4.ValueChanged += new EventHandler(tbTerrainTexture4_ValueChanged);

            editor.btnRandomScale.Click += new EventHandler(btnRandomScale_Click);
            editor.btnRandomRotation.Click += new EventHandler(btnRandomRotations_Click);

            editor.tbMaxHeight.ValueChanged += new EventHandler(tbMaxHeight_ValueChanged);

            Preferences.Default.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(Default_PropertyChanged);

            Mouse.WindowHandle = editor.ViewportHandle;
        }

        void btnAddModelFolder_Click(object sender, EventArgs e)
        {
            TreeNode node = editor.ModelFolderMenu.Tag as TreeNode;

            if (node == null)
            {
                return;
            }

            using (TextEntryForm textForm = new TextEntryForm())
            {
                textForm.Text = "Please select a name for the folder.";
                textForm.lblText.Text = "Folder Name:";

                if (textForm.ShowDialog() == DialogResult.OK)
                {
                    string nodePath = string.Empty;
                    string relativePath = string.Empty;

                    if (node.ImageIndex == 0)
                    {
                        node.Nodes.Insert(0, textForm.tbText.Text, textForm.tbText.Text, 0);

                        TreeNode newNode = node.Nodes[textForm.tbText.Text];
                        relativePath = newNode.FullPath;
                        nodePath = Path.Combine(EditorGlobals.ContentPath, newNode.FullPath);
                    }
                    else
                    {
                        if (node.Parent != null)
                        {
                            node.Parent.Nodes.Insert(node.Index, textForm.tbText.Text, textForm.tbText.Text, 0);

                            TreeNode newNode = node.Parent.Nodes[textForm.tbText.Text];
                            relativePath = newNode.FullPath;
                            nodePath = Path.Combine(EditorGlobals.ContentPath, newNode.FullPath);
                        }
                    }

                    if (string.IsNullOrEmpty(nodePath) == false && Directory.Exists(nodePath) == false)
                    {
                        Directory.CreateDirectory(nodePath);

                        EditorGlobals.AddFolderItem(relativePath);
                    }
                }
            }
        }

        void tvAssets_NodeMouseClick(object sender, System.Windows.Forms.TreeNodeMouseClickEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right && editor.tvAssets.SelectedNodes.Count == 1)
            {
                editor.ModelFolderMenu.Tag = editor.tvAssets.SelectedNode;
                editor.ModelFolderMenu.Show(editor.tvAssets, e.Location);
            }
        }

        /// <summary>
        /// Called when the selected object is changed by means other than the treeview.
        /// </summary>
        private void SelectionChanged()
        {
            editor.tvObjects.ClearSelectedNodes();

            for (int i = 0; i < gizmo.Transforms.Count; i++)
            {
                BaseObject baseObject = scene.GetBaseObject(gizmo.Transforms.Objects[i]);
                TreeNode node = editor.tvObjects.GetNodeFromGroupPath(baseObject.GroupPath, baseObject.Name);

                editor.tvObjects.ToggleNode(node, true);
                node.EnsureVisible();
            }

            editor.propertyGrid.SelectedObject = null;
            editor.propertyGrid.SelectedObjects = null;

            if (gizmo.Transforms.Count == 1)
            {
                editor.propertyGrid.SelectedObject = scene.GetBaseObject(gizmo.Transforms.Objects[0]);
            }
            else if (gizmo.Transforms.Count > 1)
            {
                object[] selected = new object[gizmo.Transforms.Count];

                for (int i = 0; i < gizmo.Transforms.Count; i++)
                    selected[i] = scene.GetBaseObject(gizmo.Transforms.Objects[i]);

                editor.propertyGrid.SelectedObjects = selected;
            }

            editor.propertyGrid.Refresh();
        }

        private void FindChangedObjects(TreeNode node, List<BaseObject> baseObjects, List<string> newPaths)
        {
            for (int i = 0; i < node.Nodes.Count; i++)
			{
                if (node.Nodes[i].ImageIndex == 0)
                {
                    FindChangedObjects(node.Nodes[i], baseObjects, newPaths);
                }
                else
                {
                    BaseObject baseObject = scene.GetBaseObject(node.Nodes[i].Text);
                    baseObjects.Add(baseObject);
                    newPaths.Add(editor.tvObjects.GetGroupPathFromNode(node.Nodes[i], false));
                }
			}

            if (node.Nodes.Count == 0)
            {
                BaseObject baseObject = scene.GetBaseObject(node.Text);
                baseObjects.Add(baseObject);
                newPaths.Add(editor.tvObjects.GetGroupPathFromNode(node, false));
            }
        }

        void tvObjects_NodesMoved(object sender, TreeNodeMovedEventArgs e)
        {
            List<string> oldGroupPaths = new List<string>();
            List<string> newGroupPaths = new List<string>();

            List<string> names = new List<string>();
            List<BaseObject> baseObjects = new List<BaseObject>();

            List<string> foldersToCleanUp =  new List<string>();

            for (int i = 0; i < e.Nodes.Count; i++)
            {
                FindChangedObjects(e.Nodes[i], baseObjects, newGroupPaths);

                if (e.Nodes[i].ImageIndex == 0)
                {
                    foldersToCleanUp.Add(e.NodePaths[i] + '|' + e.Nodes[i].Name);
                }
            }

            for (int i = baseObjects.Count - 1; i >= 0; i--)
            {
                BaseObject baseObject = baseObjects[i];

                if (baseObject != null && newGroupPaths[i] != baseObject.GroupPath)
                {
                    oldGroupPaths.Add(baseObject.GroupPath);
                    names.Add(baseObject.Name);

                    baseObject.GroupPath = newGroupPaths[i];
                }
                else
                {
                    baseObjects.RemoveAt(i);
                    newGroupPaths.RemoveAt(i); 
                }
            }

            if (oldGroupPaths.Count > 0)
            {
                undoActions.Push(new MoveObjectGroupsAction(names, oldGroupPaths, newGroupPaths, foldersToCleanUp, editor.tvObjects), true);

                editor.tvObjects.BeginUpdate();
                editor.tvObjects.Sort();
                editor.tvObjects.EndUpdate();
            }
        }

        void tvObjects_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            HandleNodeLeftClick();

            if (e.KeyCode == System.Windows.Forms.Keys.Delete)
            {
                editor.btnRemove.PerformClick();
            }
        }

        void btnAddObjectGroup_Click(object sender, EventArgs e)
        {
            TreeNode node = editor.AddObjectGroupMenu.Tag as TreeNode;

            if (node == null)
            {
                return;
            }

            using (TextEntryForm textForm = new TextEntryForm())
            {
                textForm.Text = "Please select a name for the group.";
                textForm.lblText.Text = "Group Name:";

                if (textForm.ShowDialog() == DialogResult.OK)
                {
                    if (node.ImageIndex == 0)
                    {
                        node.Nodes.Insert(0, textForm.tbText.Text, textForm.tbText.Text, 0);

                        TreeNode newNode = node.Nodes[textForm.tbText.Text];

                        string nodePath = editor.tvObjects.GetGroupPathFromNode(newNode, true);
                        undoActions.Push(new AddObjectGroupAction(nodePath, editor.tvObjects), true);
                    }
                    else
                    {
                        if (node.Parent != null)
                        {
                            node.Parent.Nodes.Insert(node.Index, textForm.tbText.Text, textForm.tbText.Text, 0);

                            TreeNode newNode = node.Parent.Nodes[textForm.tbText.Text];

                            string nodePath = editor.tvObjects.GetGroupPathFromNode(newNode, true);
                            undoActions.Push(new AddObjectGroupAction(nodePath, editor.tvObjects), true);
                        }
                    }
                }
            }
        }

        void btnRandomScale_Click(object sender, EventArgs e)
        {
            if (gizmo.Transforms.Count == 0)
            {
                return;
            }

            using (MinMaxForm minMaxForm = new MinMaxForm())
            {
                minMaxForm.tbMin.Minimum = 0M;
                minMaxForm.tbMax.Maximum = 100M;

                minMaxForm.tbMin.Value = 0.9M;
                minMaxForm.tbMax.Value = 1.1M;

                minMaxForm.tbMin.DecimalPlaces = minMaxForm.tbMax.DecimalPlaces = 3;

                if (minMaxForm.ShowDialog() == DialogResult.OK)
                {
                    for (int i = 0; i < gizmo.Transforms.Count; i++)
                    {
                        float scale = (float)((double)minMaxForm.tbMin.Value + random.NextDouble() *
                            (double)(minMaxForm.tbMax.Value - minMaxForm.tbMin.Value));

                        scene.GetBaseObject(gizmo.Transforms.Objects[i]).Scale = new Vector3(scale);
                    }
                }
            }

            changesMade = true;
        }
        void btnRandomRotations_Click(object sender, EventArgs e)
        {
            if (gizmo.Transforms.Count == 0)
            {
                return;
            }

            for (int i = 0; i < gizmo.Transforms.Count; i++)
            {
                float scale = (float)(random.NextDouble() * MathHelper.TwoPi);

                scene.GetBaseObject(gizmo.Transforms.Objects[i]).Rotation *=
                    Quaternion.CreateFromAxisAngle(Vector3.Up, scale);
            }

            changesMade = true;
        }

        private static void PopulateTreeView(System.Windows.Forms.TreeView treeView, IEnumerable<string> paths, char pathSeparator)
        {
            //TreeNode lastNode = null;
            //string subPathAgg;

            foreach (string path in paths)
            {
                string[] splitPath = path.Split(pathSeparator);
                TreeNodeCollection nodes = treeView.Nodes;

                string joinedPath = string.Empty;

                for (int i = 0; i < splitPath.Length; i++)
                {
                    joinedPath += splitPath[i];

                    bool isFile = EditorGlobals.ModelManager.Models.ContainsKey(joinedPath);

                    if (nodes.ContainsKey(splitPath[i]) == false)
                    {
                        int imageIndex = isFile ? 1 : 0;
                        TreeNode node = nodes.Add(splitPath[i], splitPath[i], imageIndex);

                        if (isFile)
                        {
                            node.Tag = joinedPath;
                        }
                    }

                    nodes = nodes[splitPath[i]].Nodes;
                    joinedPath += pathSeparator;
                }

                //subPathAgg = string.Empty;

                //foreach (string subPath in path.Split(pathSeparator))
                //{
                //    subPathAgg += subPath;

                //    string[] split = subPath.Split(pathSeparator);

                //    bool isChildNode = paths.Contains(subPathAgg);

                //    if (isChildNode == false)
                //    {
                //        subPathAgg += pathSeparator;
                //    }

                //    TreeNode[] nodes = treeView.Nodes.Find(subPathAgg, true);

                //    if (nodes.Length == 0)
                //    {
                //        if (lastNode == null)
                //        {
                //            int imageIndex = EditorGlobals.ModelManager.Models.ContainsKey(subPathAgg) ? 1 : 0;

                //            lastNode = treeView.Nodes.Add(subPathAgg, subPath, imageIndex);

                //            if (isChildNode)
                //            {
                //                lastNode.Tag = subPathAgg;
                //            }
                //        }
                //        else
                //        {
                //            int imageIndex = EditorGlobals.ModelManager.Models.ContainsKey(subPathAgg) ? 1 : 0;
                //            lastNode = lastNode.Nodes.Add(subPathAgg, subPath, imageIndex);

                //            if (isChildNode)
                //            {
                //                lastNode.Tag = subPathAgg;
                //            }
                //        }
                //    }
                //    else
                //    {
                //        lastNode = nodes[0];
                //    }
                //}
            }
        }

        private TreeNode CreateDirectoryNode(DirectoryInfo directoryInfo)
        {
            var directoryNode = new TreeNode(directoryInfo.Name, 0, 0);
            directoryNode.Name = directoryInfo.Name;

            foreach (var directory in directoryInfo.GetDirectories())
            {
                directoryNode.Nodes.Add(CreateDirectoryNode(directory));
            }

            return directoryNode;
        }

        /// <summary>
        /// Creates a new node in the asset tree for each 
        /// of the models loaded in the model manager.
        /// </summary>
        private void SetUpAssetsTree()
        {
            editor.tvAssets.Nodes.Clear();

            var rootDirectoryInfo = new DirectoryInfo(Path.Combine(EditorGlobals.ContentPath, "Models"));
            editor.tvAssets.Nodes.Add(CreateDirectoryNode(rootDirectoryInfo));

            PopulateTreeView(editor.tvAssets, modelManager.Models.Keys, Path.DirectorySeparatorChar);
        }
        /// <summary>
        /// Creates the basic object tree structure and
        /// then adds all loaded objects to the tree.
        /// </summary>
        private void SetUpObjectTree()
        {
            editor.tvObjects.Nodes.Clear();
            editor.tvObjects.SelectedNodes.Clear();

            editor.tvObjects.Nodes.Add("Objects", "Objects", 0);
            editor.tvObjects.Nodes["Objects"].Tag = true;

            foreach (string modelName in scene.ObjectNames)
            {
                AddObjectToTree(modelName, "Objects");
            }
        }

        private TreeNode AddNode(TreeNode node, string key)
        {
            if (node.Nodes.ContainsKey(key))
            {
                return node.Nodes[key];
            }
            else
            {
                return node.Nodes.Add(key, key);
            }
        }

        /// <summary>
        /// Creates a new node in the object tree to represent this object. (Object must have GroupPath set.)
        /// </summary>
        private void AddObjectToTree(BaseObject baseObject)
        {
            string[] groupPath = baseObject.GroupPath.Split('|');
            System.Windows.Forms.TreeNodeCollection treeNodes = editor.tvObjects.Nodes;

            for (int i = 0; i < groupPath.Length; i++)
            {
                if (treeNodes.ContainsKey(groupPath[i]) == false)
                {
                    treeNodes.Add(groupPath[i],
                                  groupPath[i],
                                  0);
                }

                treeNodes = treeNodes[groupPath[i]].Nodes;
            }

            treeNodes.Add(baseObject.Name, baseObject.Name, 1);
            treeNodes[baseObject.Name].Tag = false;

            editor.tvObjects.BeginUpdate();
            editor.tvObjects.Sort();
            editor.tvObjects.EndUpdate();
        }
        /// <summary>
        /// Creates a new node in the object tree to represent this object.
        /// </summary>
        private void AddObjectToTree(string objectName, string category)
        {
            BaseObject baseObject = scene.GetBaseObject(objectName);

            if (string.IsNullOrEmpty(baseObject.GroupPath))
            {
                baseObject.GroupPath = category;
            }

            AddObjectToTree(baseObject);
        }
        /// <summary>
        /// Removes the node in the object tree that represents this object.
        /// </summary>
        private void RemoveObjectFromTree(BaseObject baseObject)
        {
            TreeNode node = editor.tvObjects.GetNodeFromGroupPath(baseObject.GroupPath, baseObject.Name);
            node.Remove();
        }

        /// <summary>
        /// Moves the camera to look at the entire scene.
        /// </summary>
        private void ViewScene()
        {
            if (scene.ObjectNames.Count != 0)
            {
                GroupObject sceneObjects = new GroupObject();
                sceneObjects.AddRange(scene.ObjectNames);

                BoundingSphere nodeSphere = BoundingSphere.CreateFromBoundingBox(sceneObjects.Bounds);
                float distanceToCenter = nodeSphere.Radius / (float)Math.Sin(MathHelper.PiOver4 / 2);

                Vector3 back = -camera.Forward;
                camera.Position = nodeSphere.Center + (back * distanceToCenter);

                if (camera is MayaStyleCamera)
                {
                    (camera as MayaStyleCamera).Zoom = distanceToCenter;
                }

                Vector3 direction = nodeSphere.Center - camera.Position;
                direction.Normalize();

                if (camera is Camera)
                {
                    camera.ChangeDirection(direction);
                }
                else if (camera is MayaStyleCamera)
                {
                    camera.ChangeDirection(nodeSphere.Center);
                }

                editor.Viewport.Select();
            }
        }

        private void SetOldValues()
        {
            System.Windows.Forms.GridItem gridItem = editor.propertyGrid.SelectedGridItem;

            if (gridItem != null && gridItem.GridItemType == System.Windows.Forms.GridItemType.Property)
            {
                gridItem = GetRootGridItem(gridItem);

                oldValues = new object[gizmo.Transforms.Count];

                for (int i = 0; i < oldValues.Length; i++)
                    oldValues[i] = gridItem.Value;
            }
            else
                oldValues = null;
        }

        private System.Windows.Forms.GridItem GetRootGridItem(System.Windows.Forms.GridItem gridItem)
        {
            System.Windows.Forms.GridItem rootItem = gridItem;

            if (rootItem.PropertyDescriptor.ComponentType.IsValueType == false)
            {
                return rootItem;
            }

            while (gridItem.Parent.Parent != null)
            {
                gridItem = gridItem.Parent;

                if (gridItem.PropertyDescriptor != null &&
                    !gridItem.PropertyDescriptor.ComponentType.IsValueType)
                {
                    rootItem = gridItem;
                    break;
                }
            }

            return rootItem;
        }

        private string ChooseObjectName(string suggestedName, bool showDialog)
        {
            NewModelForm nameForm = new NewModelForm();
            string entityName = string.Empty;

            if (suggestedName == string.Empty)
            {
                TreeNode selectedItem = editor.tvAssets.SelectedNode;
                nameForm.tbText.Text = CheckName(Path.GetFileName(selectedItem.Tag as string));
            }
            else
            {
                nameForm.tbText.Text = CheckName(suggestedName);
            }

            if (showDialog == false)
            {
                return nameForm.tbText.Text;
            }

            while (entityName == string.Empty)
            {
                DialogResult textResult = nameForm.ShowDialog();

                if (textResult != DialogResult.OK)
                    return null;

                if (scene.Contains(nameForm.tbText.Text))
                    System.Windows.Forms.MessageBox.Show("An object already exists with this name");
                else
                    entityName = nameForm.tbText.Text;
            }
            return entityName;
        }

        private new void LoadContent()
        {
            editor.tvAssets.Enabled = false;

            editor.btnAddAsset.Enabled = ButtonEnabled.False;
            editor.btnRemoveAsset.Enabled = ButtonEnabled.False;

            loadingForm = new LoadingForm();
            loadingForm.Show();

            modelManager = new ModelManager(loadingForm.backgroundWorker);

            loadingForm.Close();
            loadingForm.Dispose();

            SetUpAssetsTree();

            editor.tvAssets.Enabled = true;

            editor.btnAddAsset.Enabled = ButtonEnabled.Container;
            editor.btnRemoveAsset.Enabled = ButtonEnabled.Container;

            if (dottedLine == null)
            {
                dottedLine = EditorGlobals.EditorContent.Load<Texture2D>("Editor\\DottedLine");
            }
            if (alphaRectangle == null)
            {
                alphaRectangle = EditorGlobals.EditorContent.Load<Texture2D>("Editor\\rectangle");
            }
        }

        public void AddSceneToContentProject(string filePath)
        {
            string name = Path.GetFileNameWithoutExtension(filePath);
            string link = Path.GetFileName(filePath);
            string path = Path.Combine("Scenes", link);

            EditorGlobals.AddItem(name, path);
        }

        public override void Update(GameTime gameTime)
        {
            if (editor.Resizing || !editor.Viewport.Focused)
                return;

            mouseState = Mouse.GetState();
            keyboardState = Keyboard.GetState();

            mouseRay = EngineGlobals.GetMouseRay();

            camera.Update((float)gameTime.ElapsedGameTime.TotalSeconds);

            editor.lblCameraPosition.Text = string.Format("X : {0}  Y : {1}  Z : {2}",
                camera.Position.X, camera.Position.Y, camera.Position.Z);

            bool wasManipulating = gizmo.Manipulating;

            gizmo.Update(selectingObjects, camera);

            if (!gizmo.Manipulating && wasManipulating)
            {
                if (gizmo.GizmoMode == GizmoMode.Translate)
                {
                    undoActions.Push(new MoveAction(gizmo.Transforms.Objects.ToArray(),
                        gizmo.Transforms.Position - gizmo.InitialPosition), true);
                }

                else if (gizmo.GizmoMode == GizmoMode.Rotate)
                {
                    Quaternion deltaRotation = gizmo.Transforms.Rotation;
                    Vector3[] deltaPosition = (Vector3[])gizmo.Transforms.DeltaPosition.Clone();

                    undoActions.Push(new RotateAction(gizmo.Transforms.Objects.ToArray(),
                        gizmo.Oritentation == GizmoOrientation.Camera || gizmo.Oritentation == GizmoOrientation.Local,
                        deltaRotation, deltaPosition), true);

                    gizmo.Transforms.ResetRotation();
                }

                else if (gizmo.GizmoMode == GizmoMode.Scale)
                {
                    undoActions.Push(new ScaleAction(gizmo.Transforms.Objects.ToArray(),
                        gizmo.Transforms.Scale), true);

                    gizmo.Transforms.ResetScale();
                }
            }

            if (gizmo.Manipulating)
            {
                editor.propertyGrid.Refresh();
            }

            if (scene.HeightMap != null)
            {
                scene.HeightMap.Effect.DrawCursor = false;
            }

            if (IsMouseOverViewport())
            {
                if (gizmo.Manipulating == false && wasManipulating == false)
                {
                    if (scene.HeightMap != null && editor.toolControl.SelectedTab.Text == "Terrain")
                    {
                        scene.HeightMap.Effect.DrawCursor = true;
                        EditTerrain();
                    }
                    else
                    {
                        if (mouseState.LeftButton == ButtonState.Pressed &&
                            prevMouseState.LeftButton == ButtonState.Released)
                        {
                            selectionBox = new Rectangle(mouseState.X, mouseState.Y, 0, 0);
                            selectingObjects = true;
                        }
                        else if (mouseState.LeftButton == ButtonState.Pressed &&
                                 prevMouseState.LeftButton == ButtonState.Pressed)
                        {
                            selectionBox = new Rectangle(selectionBox.X, selectionBox.Y,
                                mouseState.X - selectionBox.X, mouseState.Y - selectionBox.Y);
                            selectingObjects = true;
                        }
                        else if (mouseState.LeftButton == ButtonState.Released &&
                                 prevMouseState.LeftButton == ButtonState.Pressed)
                        {
                            selectingObjects = false;

                            if (selectionBox.Width < 2 && selectionBox.Height < 2)
                            {
                                HandleSingleClick();
                                selectionBox = new Rectangle(-1, -1, 0, 0);
                            }
                            else
                            {
                                if (selectionBox.X > -1 && selectionBox.Y > -1)
                                {
                                    GroupSelect();
                                }

                                selectionBox = new Rectangle(-1, -1, 0, 0);
                            }
                        }
                    }
                }
            }

            HandleKeyboardInput();

            scene.Update();

            prevMouseState = mouseState;
            prevKeyState = keyboardState;

            elapsedTime += gameTime.ElapsedGameTime;

            if (elapsedTime > TimeSpan.FromSeconds(1))
            {
                elapsedTime -= TimeSpan.FromSeconds(1);
                frameRate = frameCounter;
                frameCounter = 0;
            }

            base.Update(gameTime);
        }

        private void EditTerrain()
        {
            HeightMap heightMap = EngineGlobals.Scene.HeightMap;

            Triangle triangle;
            float? rayLength = heightMap.QuadTree.Intersects(ref mouseRay, out triangle);

            if (rayLength.HasValue)
            {
                Vector3 rayTarget = mouseRay.Position + mouseRay.Direction * rayLength.Value;

                heightMap.groundCursorPosition.X = ((int)(rayTarget.X / heightMap.CellSize) *
                    (int)heightMap.CellSize) / (heightMap.Size * heightMap.CellSize);

                heightMap.groundCursorPosition.Y = rayTarget.Y;

                heightMap.groundCursorPosition.Z = ((int)(rayTarget.Z / heightMap.CellSize) *
                    (int)heightMap.CellSize) / (heightMap.Size * heightMap.CellSize);

                Point pixel = new Point((int)(rayTarget.X / heightMap.CellSize),
                                        (int)(rayTarget.Z / heightMap.CellSize));

                if (mouseState.LeftButton == ButtonState.Pressed)
                {
                    switch (editor.terrainTools.CheckedButton.Name)
                    {
                        case ("btnRaise"):
                            {
                                heightMap.RaiseHeight();

                                terrainChangesMade = true;
                                changesMade = true;

                                break;
                            }
                        case ("btnLower"):
                            {
                                heightMap.LowerHeight();

                                terrainChangesMade = true;
                                changesMade = true;

                                break;
                            }
                        case ("btnSmooth"):
                            {
                                heightMap.Smooth();

                                terrainChangesMade = true;
                                changesMade = true;

                                break;
                            }
                        case ("btnRamp"):
                            {
                                heightMap.CreateRamp();

                                terrainChangesMade = true;
                                changesMade = true;

                                break;
                            }
                        case ("btnFlatten"):
                            {
                                if (flatteningTerrain == false)
                                {
                                    heightMap.FlattenHeight = heightMap.groundCursorPosition.Y;
                                    flatteningTerrain = true;
                                }
                                heightMap.FlattenVertices();

                                terrainChangesMade = true;
                                changesMade = true;

                                break;
                            }
                        case ("btnPaint"):
                            {
                                heightMap.Paint(pixel.X, pixel.Y, editor.tbTerrainTexture.SelectedIndex);

                                colorMapChangesMade = true;
                                changesMade = true;

                                break;
                            }
                    }
                }
                else
                {
                    flatteningTerrain = false;
                }

                if (mouseState.LeftButton == ButtonState.Released &&
                    prevMouseState.LeftButton == ButtonState.Pressed)
                {
                    scene.HeightMap.UpdateHeightTexture();
                    scene.HeightMap.UpdateColorTexture(true);
                }
            }
        }

        private void GroupSelect()
        {
            gizmo.Transforms.Clear();
            editor.tvObjects.ClearSelectedNodes();

            BoundingFrustum frustum = CreateSelectionFrustum();

            foreach (BaseObject e in scene.SceneObjects)
            {
                if (camera.Frustum.Contains(e.Bounds) == ContainmentType.Disjoint)
                    continue;

                if (frustum.Contains(e.Bounds) == ContainmentType.Disjoint)
                {
                    continue;
                }

                for (int i = 0; i < e.Vertices.Count / 3; i += 3)
                {
                    Vector3 v0 = Vector3.Transform(e.Vertices[i], e.World);
                    Vector3 v1 = Vector3.Transform(e.Vertices[i + 1], e.World);
                    Vector3 v2 = Vector3.Transform(e.Vertices[i + 2], e.World);

                    if (frustum.Intersects(ref v0, ref v1, ref v2))
                    {
                        gizmo.Transforms.Add(e.Name);
                        break;
                    }
                }
            }

            SelectionChanged();
        }

        private BoundingFrustum CreateSelectionFrustum()
        {
            selectionBox.X = Math.Min(selectionBox.X, selectionBox.X + selectionBox.Width);
            selectionBox.Y = Math.Min(selectionBox.Y, selectionBox.Y + selectionBox.Height);

            if (selectionBox.Width < 0)
                selectionBox.Width *= -1;
            if (selectionBox.Height < 0)
                selectionBox.Height *= -1;

            float inv_width = 1.0f / (float)selectionBox.Width;
            float inv_height = 1.0f / (float)selectionBox.Height;

            Matrix mat = Matrix.Identity;
            mat.M11 = editor.Viewport.Width * inv_width;
            mat.M22 = editor.Viewport.Height * inv_height;

            mat.M41 = ((float)editor.Viewport.Width - 2 * (float)selectionBox.Center.X) * inv_width;
            mat.M42 = -((float)editor.Viewport.Height - 2 * (float)selectionBox.Center.Y) * inv_height;

            BoundingFrustum frustum = new BoundingFrustum(camera.View * camera.Projection * mat);

            return frustum;
        }

        private void HandleSingleClick()
        {
            if (placingObjects)
            {
                Vector3? point = null;
                point = scene.GetClickedPoint(EngineGlobals.GetMouseRay());

                if (point != null)
                {
                    TreeNode selectedItem = editor.tvAssets.SelectedNode;

                    string entityName = ChooseObjectName("", keyboardState.IsKeyUp(Keys.LeftShift));

                    if (entityName != null)
                    {
                        Model model = modelManager.Models[selectedItem.Tag as string];

                        BaseObject entity = new BaseObject(entityName, model);
                        entity.ModelPath = selectedItem.Tag as string;
                        entity.Position = point.Value;

                        scene.Add(entityName, entity);
                        undoActions.Push(new AddObjectAction(entity), true);

                        AddObjectToTree(entityName, "Objects");

                        gizmo.Transforms.Clear();
                        gizmo.Transforms.Add(entity.Name);

                        SelectionChanged();
                    }
                    else
                    {
                        placingObjects = false;
                    }
                }

                if (keyboardState.IsKeyUp(Keys.LeftShift))
                {
                    placingObjects = false;
                }
            }

            else
            {
                BaseObject clickedNode = null;

                clickedNode = scene.GetClickedBaseObject(EngineGlobals.GetMouseRay(), string.Empty);

                if (clickedNode as I3DComponent != null)
                {
                    if (keyboardState.IsKeyDown(Keys.LeftShift) &&
                        keyboardState.GetPressedKeys().Length == 1)
                    {
                        if (gizmo.Transforms.Objects.Contains(clickedNode.Name))
                        {
                            gizmo.Transforms.Remove(clickedNode.Name);
                        }
                        else
                        {
                            gizmo.Transforms.Add(clickedNode.Name);
                        }
                    }
                    else
                    {
                        gizmo.Transforms.Clear();
                        gizmo.Transforms.Add(clickedNode.Name);
                    }
                }

                else
                {
                    gizmo.Transforms.Clear();
                }

                SelectionChanged();
            }
        }
        private void HandleKeyboardInput()
        {
            if (keyboardState.IsKeyUp(Keys.Delete) && prevKeyState.IsKeyDown(Keys.Delete) &&
                editor.Viewport.Focused && gizmo.Transforms.Count > 0)
            {
                BaseObject[] selectedObjects = new BaseObject[gizmo.Transforms.Objects.Count];

                for (int i = 0; i < selectedObjects.Length; i++)
                {
                    selectedObjects[i] = scene.GetBaseObject(gizmo.Transforms.Objects[i]);
                }

                undoActions.Push(new RemoveObjectAction(selectedObjects, string.Empty), true);

                foreach (string name in gizmo.Transforms.Objects)
                {
                    RemoveObjectFromTree(scene.GetBaseObject(name));
                    scene.Remove(name);
                }

                gizmo.Transforms.Clear();
            }

            if (keyboardState.IsKeyUp(Keys.LeftShift) && prevKeyState.IsKeyDown(Keys.LeftShift) &&
                placingObjects)
            {
                placingObjects = false;
            }
        }

        /// <summary>
        /// Checks if the current scene contains an object with
        /// the same name, and returns a replacement if true.
        /// </summary>
        private string CheckName(string name)
        {
            if (scene.Contains(name))
            {
                for (int i = 1; i < int.MaxValue; i++)
                {
                    if (!scene.Contains(name + "_" + i.ToString()))
                    {
                        return name + "_" + i.ToString();
                    }
                }
            }
            else
            {
                return name;
            }

            return string.Empty;
        }

        /// <summary>
        /// Returns wether the mouse is over the viewport.
        /// </summary>
        private bool IsMouseOverViewport()
        {
            int mouseX = mouseState.X;
            int mouseY = mouseState.Y;

            return mouseX >= 0 && mouseY >= 0 && mouseX <= EngineGlobals.GraphicsDevice.Viewport.Width &&
                mouseY <= EngineGlobals.GraphicsDevice.Viewport.Height;
        }

        private void DrawHorizontalLine(int thePositionY)
        {
            if (selectionBox.Width > 0)
            {
                for (int i = 0; i <= selectionBox.Width - 2; i += 2)
                    if (selectionBox.Width - i >= 0)
                        EngineGlobals.SpriteBatch.Draw(dottedLine, new Rectangle(selectionBox.X + i, thePositionY, 2, 1), Color.White);
            }
            else if (selectionBox.Width < 0)
            {
                for (int i = -2; i >= selectionBox.Width; i -= 2)
                    if (selectionBox.Width - i <= 0)
                        EngineGlobals.SpriteBatch.Draw(dottedLine, new Rectangle(selectionBox.X + i, thePositionY, 2, 1), Color.White);
            }
        }
        private void DrawVerticalLine(int thePositionX)
        {
            if (selectionBox.Height > 0)
            {
                for (int aCounter = 0; aCounter <= selectionBox.Height; aCounter += 2)
                {
                    if (selectionBox.Height - aCounter >= 0)
                    {
                        EngineGlobals.SpriteBatch.Draw(dottedLine, new Rectangle(thePositionX, selectionBox.Y + aCounter, 2, 1),
                            new Rectangle(0, 0, dottedLine.Width, dottedLine.Height), Color.White, MathHelper.ToRadians(90),
                                new Vector2(0, 0), SpriteEffects.None, 0);
                    }
                }
            }

            else if (selectionBox.Height < 0)
            {
                for (int aCounter = 0; aCounter >= selectionBox.Height; aCounter -= 2)
                {
                    if (selectionBox.Height - aCounter <= 0)
                    {
                        EngineGlobals.SpriteBatch.Draw(dottedLine, new Rectangle(thePositionX - 2, selectionBox.Y + aCounter, 2, 1), Color.White);
                    }
                }
            }
        }

        private void DrawSelectionBox()
        {
            EngineGlobals.SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);

            if ((selectionBox.Width >= 0 && selectionBox.Height >= 0) || (selectionBox.Width <= 0 && selectionBox.Height <= 0))
            {
                EngineGlobals.SpriteBatch.Draw(alphaRectangle, new Rectangle(selectionBox.X, selectionBox.Y,
                    selectionBox.Width, selectionBox.Height), new Color(150, 180, 215, 60));
            }

            else
            {
                if (selectionBox.Width < 0 && selectionBox.Height >= 0)
                {
                    EngineGlobals.SpriteBatch.Draw(alphaRectangle, new Rectangle(selectionBox.X, selectionBox.Y + selectionBox.Height,
                        selectionBox.Width, -selectionBox.Height), new Color(150, 180, 215, 60));
                }
                if (selectionBox.Height < 0 && selectionBox.Width >= 0)
                {
                    EngineGlobals.SpriteBatch.Draw(alphaRectangle, new Rectangle(selectionBox.X + selectionBox.Width, selectionBox.Y,
                        -selectionBox.Width, selectionBox.Height), new Color(150, 180, 215, 60));
                }
            }

            DrawHorizontalLine(selectionBox.Y);
            DrawHorizontalLine(selectionBox.Y + selectionBox.Height);

            //Draw the vertical portions of the selection box 
            DrawVerticalLine(selectionBox.X);
            DrawVerticalLine(selectionBox.X + selectionBox.Width);

            EngineGlobals.SpriteBatch.End();

            EngineGlobals.GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
            EngineGlobals.GraphicsDevice.BlendState = BlendState.Opaque;
            EngineGlobals.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
        }
        private void DrawGrid()
        {
            lineRenderer.Effect.World = Matrix.CreateTranslation(new Vector3(Preferences.Default.GridSpacing *
                Preferences.Default.GridLineCount / 2, 0, Preferences.Default.GridSpacing * Preferences.Default.GridLineCount / 2));

            lineRenderer.Render(camera.View, camera.Projection);
        }

        public override void Draw(GameTime gameTime)
        {
            if (editor.Resizing)
                return;

            DebugShapeRenderer.Draw(gameTime, camera.View, camera.Projection);

            frameCounter++;

            editor.lblFPS.Text = frameRate.ToString();
            editor.lblPlacing.Text = placingObjects.ToString();

            if (editor.tsSolid.Checked)
            {
                if (GraphicsDevice.RasterizerState == WireFrameState)
                {
                    GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
                }
            }
            else
            {
                if (GraphicsDevice.RasterizerState != WireFrameState)
                {
                    GraphicsDevice.RasterizerState = WireFrameState;
                }
            }

            scene.Draw(camera);

            if (Preferences.Default.GridVisible)
                DrawGrid();

            gizmo.Draw();

            DrawSelectionBox();

            GraphicsDevice.DepthStencilState = LessThanDepthState;
            ShapeRenderer.Draw(gameTime, camera.View, camera.Projection);
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;

            base.Draw(gameTime);

            GraphicsDevice.Present(null, null, editor.ViewportHandle);

            if (editor.toolControl.SelectedTab.Text == "Models" &&
                editor.kryptonHeaderGroup5.Collapsed == false)
            {
                editor.previewControl.Draw();
            }
        }
    }
}